package com.rs.mapper;

import com.jfinal.kit.Kv;
import com.jfinal.plugin.activerecord.*;
import com.rs.mapper.annotation.Paginate;
import com.rs.mapper.annotation.Query;
import com.rs.mapper.annotation.Update;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * jdk代理
 * @param <T>
 */
public class MapperProxy<T> implements InvocationHandler {

    private Class<T> methodInterface;

    public MapperProxy(Class<T> methodInterface) {
        this.methodInterface = methodInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        Kv kv = Kv.create();
        if(args!=null){
            Parameter[] ps = method.getParameters();
            for(int i=0;i<ps.length;i++){
                kv.set(ps[i].getName(),args[i]);
            }
        }
        Class<?> val = method.getDeclaringClass();
        Query query = method.getAnnotation(Query.class);
        Update update = method.getAnnotation(Update.class);
        Paginate paginate = method.getAnnotation(Paginate.class);
        String interfaceName = Mappers.interfaceName(val,method.getName());
        String db = Mappers.dbPath(val);
        if(query!=null){//查询方法
            String db1 =query.db();
            String db2 = this.getDb(db1,db);
            Class<?> t = method.getReturnType();
            Type type = method.getGenericReturnType();
            return this.query(t,type,interfaceName,db2,kv);
        }else if(update!=null){//更新和删除，新增方法
            String db1 =update.db();
            String db2 = this.getDb(db1,db);
            return this.update(interfaceName,db2,kv);
        }else if(paginate!=null){//分页
            String db1 =paginate.db();
            String db2 = this.getDb(db1,db);
            Class<?> t = method.getReturnType();
            Type type = method.getGenericReturnType();
            return this.paginate(t,type,interfaceName,db2,kv);
        }
        return null;
    }

    /**
     * 更新
     * @param interfaceName
     * @param kv
     * @return
     */
    public int update(String interfaceName,String db,Kv kv){
        DbPro pro =getDbPro(db);
        return pro.update(pro.getSqlPara(interfaceName,kv));
    }

    /**
     * 删除
     * @param interfaceName
     * @param kv
     * @return
     */
//    public int delete(String interfaceName,String db,Kv kv){
//        DbPro pro =getDbPro(db);
//        return pro.delete(pro.getSqlPara(interfaceName,kv).getSql());
//    }


    /**
     * 分页
     * @param t
     * @param type
     * @param interfaceName
     * @param kv
     * @return
     */
    public Object paginate(Class<?> t,Type type,String interfaceName,String db,Kv kv){
        DbPro pro =getDbPro(db);
        if(t.equals(Page.class)){
            Type[] typesto = ((ParameterizedType) type).getActualTypeArguments();
            if(typesto[0].equals(Record.class)){//jfinal Record返回类型
                return pro.paginate(kv.getInt("pageNumber"),kv.getInt("pageSize"),pro.getSqlPara(interfaceName,kv));
            }else{
                try{
                    Class<?> a =Class.forName(typesto[0].getTypeName());
                    Class<?> val2 =a.getSuperclass().getSuperclass();//  typesto[0].getSuperclass();
                    Object s = Mappers.getEntity(a);
                    Method val =val2.getDeclaredMethod("paginate",int.class,int.class,SqlPara.class);
                    return val.invoke(s,kv.getInt("pageNumber"),kv.getInt("pageSize"),pro.getSqlPara(interfaceName,kv));
                }catch (Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        }else{
            return null;
        }
    }


    /**
     * 查询
     * @param t
     * @param type
     * @param interfaceName
     * @param kv
     * @return
     */
    public Object query(Class<?> t,Type type,String interfaceName,String db,Kv kv){

        DbPro pro =getDbPro(db);
        if(t.equals(List.class)){
            Type[] typesto = ((ParameterizedType) type).getActualTypeArguments();
            if(typesto[0].equals(Record.class)){//jfinal Record返回类型
                return pro.find(pro.getSqlPara(interfaceName,kv));
            }else{
                try{
                    Class<?> a =Class.forName(typesto[0].getTypeName());
                    Class<?> val2 =a.getSuperclass().getSuperclass();//  typesto[0].getSuperclass();
                    Object s = Mappers.getEntity(a);
                    Method val =val2.getDeclaredMethod("find",SqlPara.class);
                    return val.invoke(s,pro.getSqlPara(interfaceName,kv));
                }catch (Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        }else{
            if(t.equals(int.class) || t.equals(Integer.class)){//返回单个值
                return pro.queryInt(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(float.class) || t.equals(Float.class)){
                return pro.queryFloat(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(BigDecimal.class)){
                return pro.queryBigDecimal(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(boolean.class) || t.equals(Boolean.class)){
                return pro.queryBoolean(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(byte.class) || t.equals(Byte.class)){
                return pro.queryByte(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(Date.class)){
                return pro.queryDate(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(double.class) || t.equals(Double.class)){
                return pro.queryDouble(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(long.class) || t.equals(Long.class)){
                return pro.queryLong(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(Number.class)){
                return pro.queryNumber(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(short.class) || t.equals(Short.class)){
                return pro.queryShort(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(Time.class)){
                return pro.queryTime(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(String.class)){
                return pro.queryStr(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(Timestamp.class)){
                return pro.queryTimestamp(pro.getSqlPara(interfaceName,kv).getSql());
            }else if(t.equals(Record.class)){//单个Record对象
                return pro.findFirst(pro.getSqlPara(interfaceName,kv));
            }else{
                try{
                    Class<?> val2 =t.getSuperclass().getSuperclass();
                    Object s = Mappers.getEntity(t);
                    Method val =val2.getDeclaredMethod("findFirst",SqlPara.class);
                    return val.invoke(s,pro.getSqlPara(interfaceName,kv));
                }catch (Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        }
    }

    private String getDb(String db1,String db){
        db1 = db1.trim();
        db =db.trim();
        if(db1.length()>0){
            return db1;
        }
        if(db.length()>0){
            return db;
        }
        return "";
    }

    private static DbPro getDbPro(String db){
        DbPro pro;
        if(db.length()>0){
            pro =Db.use(db);
        }else{
            pro =Db.use();
        }
        return pro;
    }
}
